ログインした際に、メールやSMSに認証コードが送られてくることがありますが、 その値を入力する際のUIをReactNative + typescriptで実装しました。 数値の入力inputが6つあり、入力するたびに次の要素にフォーカスが移動していくやつですね。
こんな感じのUIのイメージです。
ソースコードはこんな感じです。
ソースコード
AuthenticationCodeInput.tsx
import React, { createRef, RefObject, useRef, useState } from 'react'
import { StyleSheet, TextInput, View } from 'react-native'
/**
* const
*/
const inputLength = 6 // 何桁の認証コードか
// 認証コードで入力許可する文字の正規表現
const inputRegExp = new RegExp(/^[0-9]*$/)
/**
* style
*/
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
justifyContent: 'center',
},
itemContainer: {
backgroundColor: '#F0F0F0',
margin: 8,
borderRadius: 6,
width: 48,
height: 50,
textAlign: 'center',
fontSize: 37,
},
})
/**
* props
*/
interface AuthenticationCodeInputProps {
onInputEnd: (inputTextArr: string[]) => void
}
/**
* 認証コード入力
*/
const AuthenticationCodeInput: React.FC<AuthenticationCodeInputProps> = ({ onInputEnd }) => {
// state
const [inputArr, setInputArr] = useState<string[]>(() =>
[...Array(inputLength)].map(() => 0).map((_item) => ''),
)
const [currentIndex, setCurrentIndex] = useState(0)
// ref
const textInputRefs = useRef<Array<RefObject<TextInput>>>([])
inputArr.forEach((_, index) => {
textInputRefs.current[index] = createRef<TextInput>()
})
/**
* 入力値が変更されたとき
*/
const onChangeTextItem = (_text: string, _index: number) => {
if (_index >= 0 && _index < inputArr.length) {
const _arr = inputArr.concat()
const _currentIndex = _index + 1
const _lastText = _text.slice(-1) // 末尾の文字のみ取得(一文字になるよう制御)
// 入力値が入力条件にマッチする場合
if (inputRegExp.test(_lastText)) {
_arr[_index] = _lastText
setInputArr(_arr)
// indexが範囲内かチェック
if (_currentIndex < inputArr.length) {
setCurrentIndex(_currentIndex)
// フォーカスを次の要素に移動
textInputRefs.current[_currentIndex].current?.focus()
}
// 全て入力済みの場合
if (_arr.every((_item) => _item != null && _item !== '')) {
onInputEnd(_arr)
}
}
}
}
return (
<View style={styles.container}>
{inputArr.map((_item, _itemIndex) => (
<TextInput
key={`${_item}_${_itemIndex}`}
value={_item}
ref={textInputRefs.current[_itemIndex]}
style={styles.itemContainer}
onChangeText={(_text) => {
onChangeTextItem(_text, _itemIndex)
}}
autoFocus={_itemIndex === currentIndex}
/>
))}
</View>
)
}
export default AuthenticationCodeInput
使い方
Index.tsx
<AuthenticationCodeInput
onInputEnd={(_inputTextArr) => {
console.log('LoginPage onInputEnd()', _inputTextArr)
}}
/>
onInputEnd
メソッドで、入力完了した時の値を配列でうけとることができます。